#pragma once

#include <iostream>
#include <vector>
#include <string>
#include <pthread.h>
#include <semaphore.h>
#include "task.hpp"

// 多生产 - 多消费模型中，需要维护生产者之间的关系，也需要维护消费者之间的关系
// _psubsofQ 会成为生产者之间的公共资源，需要一把锁
// _csubsofQ 会成为消费者之间的公共资源，需要另外一把锁
template<typename T>
class circularQ
{
private:
    void trimsem(sem_t &s)
    {
        // 对 s 这个信号量做--
        // 如果s已经为0，则会将线程阻塞
        sem_wait(&s);
    }

    void addsem(sem_t &s)
    {
        // 对 s 这个信号量做++
        // 如果s 已经为 _capacity，则会将线程阻塞
        sem_post(&s);
    }
public:
    circularQ(int capacity)
        :_circularQ(capacity)
        ,_capacity(capacity)
        ,_csubsofQ(0)
        ,_psubsofQ(0)
    {
        sem_init(&_data_sem, 0, 0);
        sem_init(&_space_sem, 0, capacity);
        pthread_mutex_init(&_cmutex, nullptr);
        pthread_mutex_init(&_pmutex, nullptr);
    }

    void enqueue(const T& in)
    {
        trimsem(_space_sem);
        pthread_mutex_lock(&_pmutex);
        _circularQ[_psubsofQ] = in;
        _psubsofQ++;
        _psubsofQ %= _capacity;
        pthread_mutex_unlock(&_pmutex);
        addsem(_data_sem);
    }

    // 注意队列时先进先出的规则，所以插入数据和释放数据时，下标都是 ++ 的
    void dequeue(T *out)
    {
        trimsem(_data_sem);
        pthread_mutex_lock(&_cmutex);
        *out = _circularQ[_csubsofQ];
        _csubsofQ++;
        _csubsofQ %= _capacity;
        pthread_mutex_unlock(&_cmutex);
        addsem(_space_sem);
    }

    ~circularQ()
    {
        sem_destroy(&_data_sem);
        sem_destroy(&_space_sem);
        pthread_mutex_destroy(&_cmutex);
        pthread_mutex_destroy(&_pmutex);
    }
private:
    std::vector<T> _circularQ;
    int _capacity;

    int _csubsofQ;
    int _psubsofQ;

    sem_t _data_sem;
    sem_t _space_sem;

    pthread_mutex_t _cmutex;
    pthread_mutex_t _pmutex;
};